/****************************************************************************
                             clonegen.c
written by IL
edited by CAS
FIX: 16Mar99 - fpget - multiple fingerprints
CHG: 19mar99 - remove references to clone->flag, Gridded Poly1 - old contigC stuff
               add seqtype
CHG: 08Mar01 - to display markers of size 16
**************************************************************************/
#include "fpp.h"
#include "float.h"
#include <gtk/gtkwidget.h>  /*fred 3/5/03*/
void gelPrint2(void);
void initeditclone(int cloneindex);
void updateproj(void);
void displaymarker();

extern GtkWidget *ctg_window;  /*fred 3/5/03*/
extern int currentmarker, centreClone;
extern int cloneHigh();
extern void highlightnodraw(), highlightmarkernodraw(), removespaces();
extern void formatdate();

void initeditclone2()
{
  initeditclone(clonedisplayed);
}


/* WMN changing this to load all sizes from given file
    and store the values, primarily for MTP efficiency */
int GetSize(CLONE *clp)
{
FILE *bandsFilePtr;
char bandsFileName3[1024];
char fp[CLONE_SZ], name[CLONE_SZ];
char line[100];
int  temp, size=0, start;
int i;
int idx;
CLONE* clp1;

    if (clp->fp==NULL) return 0;

    if (clp->size_bp != 0) {
        return clp->size_bp;
    }
    if (Proj.variable) {
       if (!arrayExists(bands))
         if (fpRead() == -1) return 0;
       start = clp->fp->b1;
       for (i=0; i < clp->fp->b2; i++) 
          size += arr(bands, start + i - 1, int);
       return size;
    }
      /* cari 21.6.4 - why not null on bandsFileName3 ? */
    for (i=0; i<1024; i++) bandsFileName3[i]='\0'; 
    if (strlen(dirName) > 0)
        sprintf(bandsFileName3, "%s/Sizes/%s.sizes", dirName, clp->fp->gelname);
    else  sprintf(bandsFileName3, "Sizes/%s.sizes",  clp->fp->gelname);
    if ((bandsFilePtr = fopen(bandsFileName3, "r"))==NULL) return 0;
   
    if (clp->fp->fpchar[0]==' ') strcpy(fp,"!~&");
    else strcpy(fp, clp->fp->fpchar);

    while (1) {
      if (!fgets(line, 80, bandsFilePtr)) break;
      sscanf(line, "%s", name);
      if (fppFind(acedata, name, &idx, cloneOrder)) {
         clp1=arrp(acedata,idx, CLONE);  
         size = 0;
         while (fgets(line,80, bandsFilePtr))
         {
            sscanf(line, "%d", &temp);
            if (temp==-1) break;
            size += temp;
         }    
         clp1->size_bp = size; 
      }
    }
    fclose(bandsFilePtr);
    if (clp->size_bp == 0) {
        printf("WARNING:not able to find size information for %s\n",clp->clone);fflush(0);
    }
    return clp->size_bp;
}

/*******************************************************
                 setdefault
when the user request to change the default gel for a clone
********************************************************/
void setdefault(int box)
{
  CLONE *clone;
  struct fpdata *temp,*p1,*p2,*p3;
  int count;

  clone = arrp(acedata,clonedisplayed,CLONE);
  if(box == 1)
    printf("FPC ERROR: shouild never get this, box =1 \n");
  else{
    temp = clone->fp;
    p1 = clone->fp;
    p2 = clone->fp->next;
    if(clone->ctg == 0) count =0;
    else count = 1; 
    while(p2 != NULL){
      if(count == box-2){
	clone->fp = p2;
	p3 = p2->next;
	p2->next = temp;
	p1->next = p3;
	p2 = NULL;
      }
      else{
	p1 = p2;
	p2 = p2->next;
	count++;
      }
    }
  }
  displayclone(clonedisplayed);
}

/********************************************************
                   DEF: fpget
******************************************************/
static void fpget(int box)
{
  int k;
  struct fpdata *fp;
  CLONE *clone;
  clone = arrp(acedata,clonedisplayed,CLONE);

  fp= clone->fp;   
  if(clone->ctg == 0) box = box - 1;
  else box = box - 2;
  for(k=0;k < box && fp!=NULL; k++) /* was clonefpindex - why? */
            fp = fp->next;
  if(fp!=NULL && fp->b2 > 0){
      addfp(clonedisplayed,box);
      drawfpdata(1);
      graphPop();
  }
}
/*********************************************************
             DEF: spooky
called when a hotspot on the clone text window is picked
**********************************************************/
void spooky(int box, float x, float y)
{
  CLONE *clone;
  static int last = -1;
  struct marker *markerptr;
  struct markertop *topmarkerptr;
  struct contig *p = NULL;

  if(box == -1) last = -1;
  if(box <= 0) return;

  clone = arrp(acedata,clonedisplayed,CLONE);

/* ctg selected */
   if(box==1 && clone->ctg >0){
      if(last == box){ /* 2nd click */
	updateproj();

          if (currentctg == clone->ctg && currentctg > 0 && root != NULL) {
            for (p = root; p != NULL; p = p->new)
               if (p->next == clonedisplayed) {
                   cloneHigh(p, 1);
                   graphPop();
                   break;
               }
               if(graphActivate(g7)){ /* gets redrawn by point */ 
	          graphBoxDraw(box,WHITE,BLACK);
	          graphRedraw();
               }
          }
          else {
             highlightnodraw(FALSE);
             highlightmarkernodraw(FALSE);
             centreClone = clonedisplayed;
             centre_pos = clone->x;
             ctgdisplay(clone->ctg);
             /* graphPop();  fred 3/5/03*/
             gdk_window_raise(ctg_window->window);
          }
      }
      else { /* 1st click */
          if (last!=-1) 
	    graphBoxDraw(last,BLACK, WHITE);
	  last = box;
	  graphBoxDraw(box,WHITE,BLACK);
	  graphRedraw();
      }
      return;
    } 
/* marker selectet */

    for(topmarkerptr = clone->marker; topmarkerptr != NULL; 
                    topmarkerptr=topmarkerptr->nextmarker)
    { 
	markerptr = arrp(markerdata,topmarkerptr->markerindex,MARKER);
	if(markerptr == NULL) continue;
        if(markerptr->textbox2 != box) continue;

        if (box == last) { /*  2nd click */
	   displaymarker(topmarkerptr->markerindex);
	   if(graphActivate(gmarker))
		graphPop();
        }
        else { /* 1st click */
           if (last!=-1) 
	      graphBoxDraw(last,BLACK,WHITE);
	   last = box;
	   graphBoxDraw(box,WHITE,BLACK);
	   graphRedraw();
	}
        return;
   }

/* selected a gel */
    if(last == box) { /* 2nd click */
        fpget(box);
    }
    else{ /* 1st click */
        if (last!=-1) 
	      graphBoxDraw(last,BLACK,WHITE);
        last = box;
        graphBoxDraw(box,WHITE,BLACK);
        graphRedraw();
    }
}

void preserveit(int type)
{ 
  struct preslist *p;

  preserve = TRUE;
  if(type ==1)
    displayclone(clonedisplayed);
  else
    displaymarker(markerdisplayed);
  preserve = FALSE;

  p = preservelist;
  if(p == NULL){
    preservelist = (struct preslist *)messalloc((sizeof(struct preslist)));
    p = preservelist;
  }
  else{
    while(p->next != NULL)
      p=p->next;
    p->next = (struct preslist *)messalloc((sizeof(struct preslist)));
    p=p->next;
  }
  p->next = NULL;
  if(type ==1){
    p->graph = g7;
    g7 = 0;
  }
  else{
    p->graph = gmarker;
    gmarker = 0;
  }
}

void preserveset()
{
  preserveit(1);
}

void killallpreserved()
{
  struct preslist *p,*ptemp;

  p = preservelist;
  while(p!=NULL){
    ptemp = p;
    if(graphActivate(p->graph))
      graphDestroy();
    p = p->next;
    messfree(ptemp);
  }
  preservelist = NULL;
}

void falsepick(int box, float x, float y)
{
 
}

void displayclone(int index)
/* This routine displays information about the clone that has been double clicked */
{
  CLONE *clone;
  struct contig *p;
  struct fpdata *temp1;
  char temp[15],str1[30];
  char outstring[255], buf[20];
  BOOL last,found;
  float y=0.0;
  int i;
  int box[NBANDS],k=-1;
  struct remark *pointer;
  struct markertop *topmarkerptr;
  struct marker *markerptr;
  struct markerctgpos *pos;
  static MENUOPT amenu[] = { 
	{ graphDestroy, "Close"},
    { graphPrint,"Print Screen"},
    { 0, 0 } };
  static MENUOPT fpdispmenu1[] = { 
    { (VoidRoutine)fpget,"Fingerprint"},
    { (VoidRoutine)gelPrint2,"Gel image"},
    { 0, 0 } };
  static MENUOPT fpdispmenu2[] = { 
    { (VoidRoutine)fpget,"Fingerprint"},
    { (VoidRoutine)setdefault,"Set-To-Default"},
    { (VoidRoutine)gelPrint2,"Gel image"},
    { 0, 0 } };
  BOOL remove;

  if (index == -1) return;
  if (index>= arrayMax(acedata)) return;
  if(graphActivate(gcloneedit)) {
        graphPop();
        displaymess("Edit window open. Please Accept or Reject before opening a text window.");
        return;
  }
  displaycloneindex = arr(acedata,index,CLONE).ctg;

  if(graphActivate(g7)){  
      graphClear();
      graphPop();
      if(!preserve)
        graphRegister(PICK, spooky);
      else
        graphRegister(PICK, falsepick); 
      if (clonedisplayed != index) {
         spooky(-1,0.0,0.0);
         clonedisplayed = index;
      }
  }
  else{ 
      g7 = graphCreate (TEXT_SCROLL,"Clone",.2,.2,.26,.3) ;
      if(!preserve)
        graphRegister(PICK, spooky);
      else
        graphRegister(PICK, falsepick); 
      spooky(-1,0.0,0.0);
      clonedisplayed = index;
  }
  graphMenu(amenu);

  for(i=0;i<NBANDS;i++)
    box[i]=0;

  clone = arrp(acedata,index,CLONE);
  strcpy(temp,clone->clone);

  strcpy(outstring,clonetype[clone->class]);

  strcat(outstring," ");
  strcat(outstring,clone->clone);
  graphText(outstring,1.0,2.0);
  y = 3.0;
  if(clone->ctg > 0){
    i = graphBoxStart();
    if(!preserve)
      i = graphTextFormat(BOLD);
    graphText(clone->chctg,1.0,y);
    if(!preserve)
      i = graphTextFormat(i);
    graphBoxEnd();

    if(clone->x !=  0 || clone->y != 0){
      strcpy(outstring," ");
      itoa(clone->x,str1);
      strcat(outstring," ");
      strcat(outstring,str1);
      strcat(outstring," ");
      itoa(clone->y,str1);
      strcat(outstring,str1);
      graphText(outstring,2.0+strlen(clone->chctg),y);
    }
  }
  y += 1.0;
    
  if (clone->ctg!=clone->oldctg || clone->ibc) { /* ADD 10june99, 17Aug99 */
    if (clone->ctg!=clone->oldctg && clone->ibc)
       sprintf(outstring,"Old ctg%d CpM",clone->oldctg);
    else if (clone->ctg!=clone->oldctg)
       sprintf(outstring,"Old ctg%d",clone->oldctg);
    else sprintf(outstring,"CpM");
    graphText(outstring,1.0,y);
    y += 1.0;
  }
  if ((i=GetSize(clone))) {
    sprintf(outstring,"Size %d", i);
    graphText(outstring,1.0,y);
    y += 1.0;
  }
  i=0;

  formatdate(&(clone->creation_date), buf);
  sprintf(str1,"Created  %s ", buf);
  y += 1.0;
  graphText(str1,1.0,y);  

  formatdate(&(clone->modified_date), buf);
  sprintf(str1,"Modified %s", buf);
  y += 1.0;
  graphText(str1,1.0,y);
  y += 2.0;

  temp1 = clone->fp;
  while(temp1 != NULL){
    if(temp1->fpchar[0] != ' '){
      strcpy(outstring,"Fp Name ");
      strcat(outstring,temp1->fpchar);
      graphText(outstring,1.0,y);
      y = y + 1.0;
    }
    box[i]=graphBoxStart();
    if(!preserve){
      if(i>0)
	graphBoxMenu(box[i], fpdispmenu2);
      else
	graphBoxMenu(box[i], fpdispmenu1);
    }
    sprintf(outstring,"Gel %s", temp1->gelname);
    if(!preserve)
      k = graphTextFormat(BOLD);
    graphText(outstring,1.0,y);
    if(!preserve)
      k = graphTextFormat(k);
    graphBoxEnd();
    i++;
    y += 1.0;
    
    strcpy(outstring,"Bands ");
    
    itoa(temp1->b1,str1);
    strcat(outstring,str1);
    strcat(outstring," ");
    itoa(temp1->b2,str1);
    strcat(outstring,str1);
    graphText(outstring,1.0,y);
    y += 1.0;
    temp1 = temp1->next;
  }

  if (clone->seqtype!=0 || clone->seqstat!=0) 
  {
    y= y+1.0;
    graphText("Shotgun",1.0,y);
    sprintf(str1,"%6s %s",seqtype1[clone->seqtype], seqstat[clone->seqstat]);
    graphText(str1,9.0,y++);
  }
  pointer = clone->remark;
  if(pointer!=NULL) {
    y += 1.0;
    graphText("Remarks:",1.0,y);
    y += 1.0;
  }
  while(pointer != NULL){
    graphText(pointer->message,2.0,y);
    y += 1.0;
    pointer = pointer->next;
  }
  pointer = clone->fp_remark;
  if(pointer!=NULL) {
    y += 1.0;
    graphText("Fp_remarks:",1.0,y);
    y += 1.0;
  }
  while(pointer != NULL){
    graphText(pointer->message,2.0,y);
    y +=  1.0;
    pointer = pointer->next;
  }

  texthigh.markerbox2 = 0; /* no marker is highlighted in the clone info box */
  if(clone->marker !=NULL){
    int c;
    y += 1.0;
    topmarkerptr = clone->marker;
    graphText("Markers: ",1.0,y);
    y += 1.0;
    while(topmarkerptr != NULL){ /*for each marker */
      markerptr = arrp(markerdata,topmarkerptr->markerindex,MARKER);
      if(markerptr != NULL){ 
	markerptr->textbox2 = graphBoxStart();
	if(!preserve)
	  i =  graphTextFormat(BOLD);
	graphText(markerptr->marker, 2.0, y);
	if(!preserve)
	  i = graphTextFormat(i);
	pos = markerptr->pos;
	found = FALSE;
	while(pos != NULL && !found){
	  if(pos->ctg == clone->ctg)
	    found = TRUE;
	  if(!found)
	    pos = pos->next;
	}
	if(found){
          c=' ';
          if(markerptr->anchor){
              if (markerptr->frame_type== FRAME) c = 'F';
              else c = 'P';
          }
	  sprintf(str1," %d %c ",pos->pos, c);
	  graphText(str1,18.0, y); /* CHG 3/8/1 = quite overwriting */
	}
        if (topmarkerptr->new==1)
	  graphText("New",25.0,y);
        else if (topmarkerptr->new==2)
	  graphText("CpM",25.0,y);
	else if(topmarkerptr->weak)
	  graphText("Weak",25.0,y);
	graphBoxEnd();
	y += 1.0;
      }
      topmarkerptr = topmarkerptr->nextmarker;
    }
  }
  
  if(clone->mattype == 0){
    strcat(outstring,"\n");
  }
  else if(clone->mattype & PARENT || clone->mattype & PSPARENT ){    
    y += 1.0;
    graphText("Buried clones:",1.0,y);
    y += 1.0;
    last = FALSE;
    if(currentctg != clone->ctg || root == NULL){
      for(i=0;i<arrayMax(acedata);i++){
	clone = arrp(acedata,i, CLONE);
	if(clone->parent == clonedisplayed){
	  if(clone->mattype & EXACT ){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Exact Match)");
	    graphText(outstring,2.0,y);
	    y += 1.0;
	  }
	  else if(clone->mattype & APPROX){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Approx Match)");
	  graphText(outstring,2.0,y);
	    y += 1.0;
	  }
	  else if(clone->mattype & PSEUDO){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Psuedo Match)");
	    graphText(outstring,2.0,y);
	    y += 1.0;
	  }     
	}
      }
    }
    else{
      p= root;
      remove = FALSE;
      while(!last){
	clone = arrp(acedata,p->next, CLONE);
	if(clone->parent == clonedisplayed){
	  if(clone->mattype & EXACT ){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Exact Match)");
	    graphText(outstring,2.0,y);
	    y += 1.0;
	  }
	  else if(clone->mattype & APPROX){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Approx Match)");
	    graphText(outstring,2.0,y);
	    y += 1.0;
	  }
	  else if(clone->mattype & PSEUDO){
	    strcpy(outstring,clone->clone);
	    strcat(outstring," (Pseudo Match)");
	    graphText(outstring,2.0,y);
	    y += 1.0;
	  }     
	}
	if(p->new==NULL)
	  last = TRUE;
	p = p->new;
      } /* end while */
    }
  }
  else{
    y += 1.0;
    strcpy(outstring,"Parent ");
    strcat(outstring,clone->match);
    if(clone->mattype & EXACT) strcat(outstring," (Exact)");
    else if(clone->mattype & APPROX) strcat(outstring," (Approx)");
    else strcat(outstring," (Pseudo)");
    
    graphText(outstring,1.0,y);
    y += 1.0;
  }
     /* 1 nov 1998 
  y+=1.0;
  graphText("Band Values:",1.0,y);
  
  if (!bands)
     graphText("Bands not read yet",1.0,y+1.0);
  else {
    if (clone->fp!=NULL) {
     temp1 = clone->fp;
     for(j=0;j<temp1->b2;j++){
       y+=1.0;
       sprintf(outstring,"%d",arr(bands,temp1->b1+(j-1),int));
       graphText(outstring,2.0,y);
     } 
   }
  }
  y+=1.0;
  */
  if(!merging && !preserve)
    graphButton("Edit",initeditclone2,0.0,0.0);

  if(!preserve)
    graphButton("Preserve",preserveset,6.0,0.0);
  
  graphTextBounds(6, (int) y+0.5);

  graphRedraw();
}


/**************************************************************
                 DEF: find_Clone
***************************************************************/
BOOL find_Clone(int ctg)
/* This routine creates a linked list of structures contig which */
/* contain information needed about each clone in the contig ctg */
{
  int i, next;
  CLONE *clone;

  if ( contigs[ctg].count==0) {
      printf("FPC ERROR ctg %d count %d\n", ctg, contigs[ctg].count);
      return FALSE;
  }
  if(root != NULL) 
    messfree(root);
  
  root = (struct contig *)
         messalloc((sizeof(struct contig) * contigs[ctg].count)); 

  next = contigs[ctg].start;                     
  contigs[ctg].left = INT_MAX;
  contigs[ctg].right = INT_MIN;

  for (i=0; i < contigs[ctg].count && next != -1; i++)
  {
      clone =  arrp(acedata, next, CLONE);
      if(clone->ctg != ctg){
        printf("FPC ERROR clone %s is in ctg %d and not %d\n",
               clone->clone,clone->ctg,ctg);
        return FALSE;
      }
      if(clone->x < contigs[ctg].left)
                  contigs[ctg].left = clone->x;
      if(clone->y > contigs[ctg].right)
                  contigs[ctg].right = clone->y;
      root[i].next = next;
      if (i< contigs[ctg].count - 1)
         root[i].new = (struct contig *)  &root[i+1];  
      else root[i].new = NULL;
      root[i].box = root[i].chbox = 0;
      next = clone->next;
  }
  if (i!=contigs[ctg].count || next != -1) {
      printf("FPC ERROR ctg count %d next %d\n", contigs[ctg].count,next);
      return FALSE;
  }
  return TRUE;
}

/**************************************************************
                 DEF: sortctg
***************************************************************/
int sortctg(const void *orig_a, const void *orig_b)
{
  int x1, x2;

  struct contig *a;
  struct contig *b;

  a = (struct contig *)orig_a;
  b = (struct contig *)orig_b;

  
   x1 = arr(acedata, a->next, CLONE).x;
   x2 = arr(acedata, b->next, CLONE).x;
   if (x1 < x2) return -1;
   if (x1 > x2) return 1;
   return 0;
}
/****************************************************************
                  DEF: orderclones
****************************************************************/
void orderclones(int ctg)
{
  int i,count;

  count = contigs[ctg].count;
  if (count <= 1) return;

  qsort(root, count, sizeof(struct contig), sortctg);
  for(i=0;i<count-1;i++) root[i].new = &(root[i+1]);
  root[i].new = NULL;
}


int PositionClone(int x, int y,int *pt1, int *pt2)
/* This routine finds/calculates the position for the bullet point and the character */
/* string for the clone. x and y are the y start and finish position of the clone. */
/* i.e. the bullet must lie between this region. pt1 is the y position for the bullet */
/* and character output of the clone. pt2 is the colomn number in which the characters */
/* are to be printed out. */
{
  int i,k,j;
  BOOL found;
  CLONEPOS position;
  
/* The logic is a bit fuzzy here but basically we check each colomn and if the new */
/* clone's bullet cannot fit in.  i.e.found = FALSE then the next colomn is tried. i.e. if */
/* we come to the end of a colomn and found is still TRUE then the bullet will fit */
/* in this colomn */

  for(j=0;j<10;j++){
    for(i=x; i<=y; i++){
      found = TRUE;
      for(k=0; k<arrayMax(clonepos); k++){
	position = arr(clonepos,k,CLONEPOS);
	if(position.pos[j] == i){
	  found = FALSE;
	  break;
	}
      }
      if(found){
	array(clonepos,k,CLONEPOS).pos[j] = i;
	*pt1 = j;
	*pt2 = i;
	return(1);
      }
    }
  }

    return(-1);
}

/*********************************************************************
                   DEF: requestClone
Yellow Clone: box on contig display results in calling this
********************************************************************/
void requestClone(char *temp)
{
  int index;
  char str1[80];
  CLONE *clone;
  struct contig *p;

  removespaces(temp);
  if(!fppFind(acedata,temp,&index, cloneOrder)){              /* find clone */
    sprintf(str1,"*ERROR could not find clone %s",temp);
    displaymess(str1);
    return;
  }
  clone = arrp(acedata,index,CLONE);
  if(clone->ctg != currentctg){
      displayclone(index);
      return;
  }
  for (p = root; p != NULL; p = p->new)
      if (p->next == index) {
          cloneHigh(p, 1);
          return;
      }
}
